/*
 * This code is for a 4 channel receiver of remote control RC
 * Using 1 nRF24L01 transceiver to another, on 2 devices acting as "nodes".
 * Referance: https://nrf24.github.io/RF24/
 * 
 * 22072023 Create a PPM encoding signal and send to Phoenix RC
 * 
 * Connection:
 * NRF24L01+ PA: CE: Chip Enable; CSN: Chip Select Negtive
 * 
 * NRF24L01+ PA Connection with PRO Mini
 *   1 GND  - GND VCC  - 3.3V 
 *   3 CE   - D7  CSN  - D8
 *   5 SCK  - 13  MOSI - 11
 *   7 MISO - 12 IRQ  - None
 *   
 * NRF24L01+ PA Connection with MEGA
 *   1 GND  - GND VCC  - 3.3V 
 *   3 CE   - 53  CSN  - 49
 *   5 SCK  - 52  MOSI - 51
 *   7 MISO - 50  IRQ  - None
 *   
 * NRF24L01+ PA Connection with NANO
 *   1 GND  - GND VCC  - 3.3V
 *   3 CE   - 9  CSN  - 10
 *   5 SCK  - D13 MOSI - D11
 *   7 MISO - D12 IRQ  - None
 *
 * NRF24L01+ PA Connection with NANO IO Shield 1.0 Red
 *   1 GND  - GND VCC  - 3.3V
 *   3 CE   - D9  CSN  - D10
 *   5 SCK  - D13 MOSI - D11
 *   7 MISO - D12 IRQ  - None
 *    
 * 4 channel JoyStick connection with NANO as a transmitter
 *    Throttle        - A0
 *    Rudder(Roll)    - A1
 *    Pitch(Elevator) - A2
 *    Yaw (AIL)       - A3
 *    Throttle,Rudder, Elevator, Aileron  
 *  
 * PPM output pin: D2
 *   
 * History:
 * V0.0 KendinYap https://www.rcpano.net/2020/02/17/simple-and-cheap-radio-control-making-for-rc-models-diy-rc/
 * V0.1 25.06.2023 SH first adaption
 * V0.2 22.07.2023 Create a PPM encoding signal and send to Phoenix RC
 */


// 4 Channel Reciever

#include <SPI.h>
#include "printf.h"
#include "RF24.h"
//#include <Servo.h>

#include "PPMEncoder.h"

// Add xxx.h into the same folder of ino file
// then include "xxx.h"
//#include "nRF24L01.h"
//#include "RF24.h"

// Mega: CE   - 53 CSN  - 49   
// Nano: CE   - D7 CSN  - D8
// Nano shield: 9, 10
#define CE_PIN 9
#define CSN_PIN 10

// ppm output
#define OUTPUT_PIN 2

// instantiate an object for the nRF24L01 transceiver
RF24 radio(CE_PIN, CSN_PIN);

//IMPORTANT: The same as in the transmitter 0xE9E8F0F0E1LL
const uint64_t pipeIn = 0xE9E8F0F0E1LL;

// Let these addresses be used for the pair
 uint8_t address[][6] = { "1Node", "2Node" };
// It is very helpful to think of an address as a path instead of as
// an identifying device destination

// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1;  // 0 uses address[0] to transmit, 1 uses address[1] to transmit

// Used to control whether this node is sending or receiving
bool role = false;  // true = TX role, false = RX role

// For testing communication, we'll be using a payload containing
// a single float number that will be incremented
// on every successful transmission
float payload = 0.0;

// PWM signal
int ch_width_1 = 0, ch_width_2 = 0, ch_width_3 = 0, ch_width_4 = 0, ch_width_5 = 0, ch_width_6 = 0;

//Servo ch1; Servo ch2; Servo ch3; Servo ch4; Servo ch5; Servo ch6;

// 6 channel
struct Signal {
  byte throttle;
  byte pitch;
  byte roll;
  byte yaw;
  byte gyr; 
  byte pit;
};

Signal data;

int count=0;

// Define the initial value of each data input.
void ResetData()
{
  // The middle position for Potential meters. (254/2=127)
  data.throttle = 0; // Motor Stop when Signal lost | 信号丢失时，关闭油门Throttle)
  data.pitch = 127; // Center (Signal lost position | 俯仰通道Elevator)
  data.roll = 127; // Center (Signal lost position | 横滚通道Aileron(中心点127))
  data.yaw = 127; // Center (Signal lost position | 航向通道Rudder )
  data.gyr = 0; // Channel 5
  data.pit = 0; //Channel 6
} // ResetData


void setup(){
  
  Serial.begin(115200); //115200
  while (!Serial) {
    // some boards need to wait to ensure access to serial over USB
  }

  // Set the pins for each PWM signal
  //ch1.attach(2); //D2: THR
  //ch2.attach(3); //D3: ELE = Pitch
  //ch3.attach(4); //D4: RUD = Roll
  //ch4.attach(5); //D5: AIL = Yaw
  //ch5.attach(6);
  //ch6.attach(9);

  ResetData();
  
  // Comfigure NRF24L01
  // initialize the transceiver on the SPI bus
  if (!radio.begin()) {
    Serial.println(F("radio hardware is not responding!!"));
    while (1) {}  // hold in infinite loop
  }
  // Set the PA Level low to try preventing power supply related problems
  // because these examples are likely run with nodes in close proximity to
  // each other.
  // radio.setPALevel(RF24_PA_LOW);  // RF24_PA_MAX is default. 

  // save on transmission time by setting the radio to only transmit the
  // number of bytes we need to transmit a float
  radio.setPayloadSize(sizeof(payload));  // float datatype occupies 4 bytes
  
  // set the RX address of the TX node into a RX pipe
  radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
  // Serial.println((int)address[0]);
  // Serial.println(pipeIn); 
  //radio.openReadingPipe(1,pipeIn);//Same as the code from the transmitter,
  radio.startListening(); //start the radio comunication for receiver
  //pinMode(LED_BUILTIN,OUTPUT);//LED推挽输出
  //digitalWrite(LED_BUILTIN,HIGH);

  ppmEncoder.begin(OUTPUT_PIN);
  // CH0: roll/AIL, CH1: pitch/ELE, CH2: throttle, CH3: yaw /RUD
  ppmEncoder.setChannelPercent(0, map(data.roll, 0, 255, 0, 100));
  ppmEncoder.setChannelPercent(1, map(data.pitch, 0, 255, 0, 100));
  ppmEncoder.setChannelPercent(2, map(data.throttle, 0, 255, 0, 100));
  ppmEncoder.setChannelPercent(3, map(data.yaw, 0, 255, 0, 100));
  ppmEncoder.setChannelPercent(4, 0);
  ppmEncoder.setChannelPercent(5, 0);
  ppmEncoder.setChannelPercent(6, 0);
  ppmEncoder.setChannelPercent(7, 0);
  
} // End of Setup

unsigned long lastRecvTime = 0;
void recvData()
  {
    while (radio.available() ) 
    {
      radio.read(&data, sizeof(Signal));//receive the data 
      lastRecvTime = millis();   //Current time ms
    }
  } // End of recvData

void loop(){

   // RX node message &pipe
   //uint8_t pipe;
   //if (radio.available(&pipe)) {              // is there a payload? get the pipe number that recieved it
        //uint8_t bytes = radio.getPayloadSize();  // get the size of the payload
        //radio.read(&payload, bytes);             // fetch payload from FIFO
        //Serial.print(F("Received "));
        //Serial.print(bytes);  // print the size of the payload
        //Serial.print(F(" bytes on pipe "));
        //Serial.print(pipe);  // print the pipe number
        //Serial.print(F(": "));
        //Serial.println(payload);  // print the payload's value
     //}
     
  //Receive data from Transmitter
  recvData();
  
  unsigned long now = millis();
  if ( now - lastRecvTime > 1000 ) {
    ResetData(); //Time out large than 1 second, Signal lost.. Reset data
    Serial.println("Signal lost or Timeout > 1s");
    //digitalWrite(LED_BUILTIN,HIGH);
   }

  Serial.print("A-E-T-R"); //Ail>>roll, ELE>>pitch, THR, RUD>>yaw    
  Serial.print("\t"); Serial.print(data.roll);
  Serial.print("\t"); Serial.print(data.pitch);
  Serial.print("\t"); Serial.print(data.throttle);  
  Serial.print("\t"); Serial.println(data.yaw);
  // PWM output with width 1ms~2ms/20ms, Mapping 0~255 to 1000~2000
  ch_width_1 = map(data.throttle, 0, 255, 0, 100);     //
  ch_width_2 = map(data.pitch,    0, 255, 0, 100);     // 
  ch_width_3 = map(data.roll,     0, 255, 0, 100);     // 
  ch_width_4 = map(data.yaw,      0, 255, 0, 100);     // 
  
  // Write/Output the PWM signal
  //ch1.writeMicroseconds(ch_width_1);
  //ch2.writeMicroseconds(ch_width_2);
  //ch3.writeMicroseconds(ch_width_3);
  //ch4.writeMicroseconds(ch_width_4);
  //ch5.writeMicroseconds(ch_width_5);
  //ch6.writeMicroseconds(ch_width_6);
  //Serial.print("\t"); Serial.print(ch_width_1);
  //Serial.print("\t"); Serial.print(ch_width_2);
  //Serial.print("\t"); Serial.print(ch_width_3);
  //Serial.print("\t"); Serial.println(ch_width_4);
  //Serial.print("\t"); Serial.print(ch_width_5);
  //Serial.print("\t"); Serial.println(ch_width_6);

  // ppm signal
  // CH0: roll, CH1: pitch, CH2: throttle, CH3: yaw 
  ppmEncoder.setChannelPercent(0, ch_width_3);
  ppmEncoder.setChannelPercent(1, ch_width_2);
  ppmEncoder.setChannelPercent(2, ch_width_1);
  ppmEncoder.setChannelPercent(3, ch_width_4);
  ppmEncoder.setChannelPercent(4, 0);
  ppmEncoder.setChannelPercent(5, 0);
  ppmEncoder.setChannelPercent(6, 0);
  ppmEncoder.setChannelPercent(7, 0);

  //delay (1000);
} // End of loop